
package com.xing.disruptor.logger;

import com.lmax.disruptor.EventFactory;
import org.slf4j.Marker;
/**
 * When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during
 * the life of the RingBuffer.
 */
public class RingBufferLogEvent {

    /** The {@code EventFactory} for {@code RingBufferLogEvent}s. */
    public static final Factory FACTORY = new Factory();

    private static final long serialVersionUID = 8462119088943934758L;

    /**
     * Creates the events that will be put in the RingBuffer.
     */
    private static class Factory implements EventFactory<RingBufferLogEvent> {

        @Override
        public RingBufferLogEvent newInstance() {
            final RingBufferLogEvent result = new RingBufferLogEvent();
//            if (Constants.ENABLE_THREADLOCALS) {
//                result.messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
//                result.parameters = new Object[10];
//            }
            return result;
        }
    }

    private int threadPriority;
    private long threadId;
    private long nanoTime;
    private short parameterCount;
    private boolean includeLocation;
    private boolean endOfBatch = false;
    private String threadName;
    private String loggerName;
    private String messageFormat;
    private StringBuilder messageText;
    private Object[] parameters;
    private transient Throwable thrown;
    private Marker marker;
    private String fqcn;
    private StackTraceElement location;

//    private transient AsyncLogger asyncLogger;

//    public void setValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker,
//                          final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
//                          final StringMap mutableContextData, final ContextStack aContextStack, final long threadId,
//                          final String threadName, final int threadPriority, final StackTraceElement aLocation,
//                          final Clock clock, final NanoClock nanoClock) {
//        this.threadPriority = threadPriority;
//        this.threadId = threadId;
//        this.level = aLevel;
//        this.threadName = threadName;
//        this.loggerName = aLoggerName;
//        setMessage(msg);
//        initTime(clock);
//        this.nanoTime = nanoClock.nanoTime();
//        this.thrown = aThrowable;
//        this.thrownProxy = null;
//        this.marker = aMarker;
//        this.fqcn = theFqcn;
//        this.location = aLocation;
//        this.contextData = mutableContextData;
//        this.contextStack = aContextStack;
//        this.asyncLogger = anAsyncLogger;
//    }

//    private void initTime(final Clock clock) {
//        if (message instanceof TimestampMessage) {
//            instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
//        } else {
//            instant.initFrom(clock);
//        }
//    }

//    @Override
//    public LogEvent toImmutable() {
//        return createMemento();
//    }

//    private void setMessage(final Message msg) {
//        if (msg instanceof ReusableMessage) {
//            final ReusableMessage reusable = (ReusableMessage) msg;
//            reusable.formatTo(getMessageTextForWriting());
//            messageFormat = reusable.getFormat();
//            if (parameters != null) {
//                parameters = reusable.swapParameters(parameters);
//                parameterCount = reusable.getParameterCount();
//            }
//        } else {
//            this.message = InternalAsyncUtil.makeMessageImmutable(msg);
//        }
//    }

//    private StringBuilder getMessageTextForWriting() {
//        if (messageText == null) {
//            // Should never happen:
//            // only happens if user logs a custom reused message when Constants.ENABLE_THREADLOCALS is false
//            messageText = new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
//        }
//        messageText.setLength(0);
//        return messageText;
//    }

    /**
     * Event processor that reads the event from the ringbuffer can call this method.
     *
     * @param endOfBatch flag to indicate if this is the last event in a batch from the RingBuffer
     */
    public void execute(final boolean endOfBatch) {
        this.endOfBatch = endOfBatch;
//        asyncLogger.actualAsyncLog(this);
    }

    /**
     * Returns {@code true} if this event is the end of a batch, {@code false} otherwise.
     *
     * @return {@code true} if this event is the end of a batch, {@code false} otherwise
     */
//    @Override
//    public boolean isEndOfBatch() {
//        return endOfBatch;
//    }
//
//    @Override
//    public void setEndOfBatch(final boolean endOfBatch) {
//        this.endOfBatch = endOfBatch;
//    }
//
//    @Override
//    public boolean isIncludeLocation() {
//        return includeLocation;
//    }
//
//    @Override
//    public void setIncludeLocation(final boolean includeLocation) {
//        this.includeLocation = includeLocation;
//    }
//
//    @Override
//    public int length() {
//        return messageText.length();
//    }
//
//    @Override
//    public char charAt(final int index) {
//        return messageText.charAt(index);
//    }
//
//    @Override
//    public CharSequence subSequence(final int start, final int end) {
//        return messageText.subSequence(start, end);
//    }
//
//
//    @Override
//    public StackTraceElement getSource() {
//        return location;
//    }
//
//    public long getNanoTime() {
//        return nanoTime;
//    }

//    /**
//     * Release references held by ring buffer to allow objects to be garbage-collected.
//     */
//    public void clear() {
//        this.asyncLogger = null;
//        this.loggerName = null;
//        this.marker = null;
//        this.fqcn = null;
//        this.level = null;
//        this.message = null;
//        this.messageFormat = null;
//        this.thrown = null;
//        this.thrownProxy = null;
//        this.contextStack = null;
//        this.location = null;
//        if (contextData != null) {
//            if (contextData.isFrozen()) { // came from CopyOnWrite thread context
//                contextData = null;
//            } else {
//                contextData.clear();
//            }
//        }
//
//        // ensure that excessively long char[] arrays are not kept in memory forever
//        StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE);
//
//        if (parameters != null) {
//            for (int i = 0; i < parameters.length; i++) {
//                parameters[i] = null;
//            }
//        }
//    }
//
//    private void writeObject(final java.io.ObjectOutputStream out) throws IOException {
//        getThrownProxy(); // initialize the ThrowableProxy before serializing
//        out.defaultWriteObject();
//    }
//
//    /**
//     * Creates and returns a new immutable copy of this {@code RingBufferLogEvent}.
//     *
//     * @return a new immutable copy of the data in this {@code RingBufferLogEvent}
//     */
//    public LogEvent createMemento() {
//        return new Log4jLogEvent.Builder(this).build();
//
//    }

//    /**
//     * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code RingBufferLogEvent}.
//     * @param builder the builder whose fields to populate
//     */
//    public void initializeBuilder(final Log4jLogEvent.Builder builder) {
//        builder.setContextData(contextData) //
//                .setContextStack(contextStack) //
//                .setEndOfBatch(endOfBatch) //
//                .setIncludeLocation(includeLocation) //
//                .setLevel(getLevel()) // ensure non-null
//                .setLoggerFqcn(fqcn) //
//                .setLoggerName(loggerName) //
//                .setMarker(marker) //
//                .setMessage(getNonNullImmutableMessage()) // ensure non-null & immutable
//                .setNanoTime(nanoTime) //
//                .setSource(location) //
//                .setThreadId(threadId) //
//                .setThreadName(threadName) //
//                .setThreadPriority(threadPriority) //
//                .setThrown(getThrown()) // may deserialize from thrownProxy
//                .setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy
//                .setInstant(instant) //
//        ;
//    }

}
